package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.model.entity.*;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.web.admin.mapper.*;
import com.atguigu.lease.web.admin.service.ApartmentInfoService;
import com.atguigu.lease.web.admin.service.ApartmentLabelService;
import com.atguigu.lease.web.admin.service.LabelInfoService;
import com.atguigu.lease.web.admin.service.RoomInfoService;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentDetailVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentItemVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentQueryVo;
import com.atguigu.lease.web.admin.vo.fee.FeeValueVo;
import com.atguigu.lease.web.admin.vo.graph.GraphVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liubo
 * @description 针对表【apartment_info(公寓信息表)】的数据库操作Service实现
 * @createDate 2023-07-24 15:48:00
 */
@Service
public class ApartmentInfoServiceImpl extends ServiceImpl<ApartmentInfoMapper, ApartmentInfo>
        implements ApartmentInfoService {

    @Autowired
    private ApartmentLabelService apartmentLabelService ;

    @Autowired
    private LabelInfoMapper labelInfoMapper;

    @Autowired
    private ApartmentFacilityMapper apartmentFacilityMapper ;

    @Autowired
    private FacilityInfoMapper facilityInfoMapper ;

    @Autowired
    private ApartmentFeeValueMapper apartmentFeeValueMapper;

    @Autowired
    private FeeValueMapper feeValueMapper ;

    @Autowired
    private GraphInfoMapper graphInfoMapper ;

    @Autowired
    private RoomInfoMapper roomInfoMapper ;

    @Autowired
    private RoomInfoService roomInfoService ;

    @Override
    public IPage<ApartmentItemVo> pageItem(IPage page, ApartmentQueryVo queryVo) {
        // baseMapper的第一个参数如果传输的是IPage实例，则拦截器会进行拦截做分页处理
        return baseMapper.pageItem(page,queryVo);
    }

    @Override
    public ApartmentDetailVo getDetailById(Long id) {
        // 1. 查询公寓本身的信息
        ApartmentInfo apartmentInfo = this.getById(id);
        // 准备属性复制
        ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo();
        BeanUtils.copyProperties(apartmentInfo,apartmentDetailVo);

        // 2. 查询公寓各种关联的信息：标签、配套、图片、杂费
        // 1) 标签列表
        List<ApartmentLabel> apartmentLabelList = apartmentLabelService.list(new LambdaQueryWrapper<ApartmentLabel>().eq(ApartmentLabel::getApartmentId, id));
        List<LabelInfo> labelInfoList = apartmentLabelList.stream().map(apartmentLabel -> labelInfoMapper.selectById(apartmentLabel.getLabelId()))
                .collect(Collectors.toList());
        // 2) 配套列表
        List<ApartmentFacility> apartmentFacilityList = apartmentFacilityMapper.selectList(new LambdaQueryWrapper<ApartmentFacility>().eq(ApartmentFacility::getApartmentId, id));
        List<FacilityInfo> facilityInfoList = apartmentFacilityList.stream().map(apartmentFacility -> facilityInfoMapper.selectById(apartmentFacility.getFacilityId()))
                .collect(Collectors.toList());

        // 数据库设计范式的目的是： 使得数据库设计更规范，尽量的减少或者避免数据冗余
        // 数据库设计范式： 常规情况下，包含七大范式。但是在实际开发应用中，我们一般只应用前三个范式
        // 第一范式： 列不可再分
        // 以下设计不符合第一范式：
        /*
            uid   username    address
            u01   张三         上海市松江区谷阳北路688号大江商厦400
            u02   李四         上海市松江区谷阳南路88号
         */
        // 第二范式： 在满足第一范式的基础之上，保证一张表只表达一个含义
        // 以下设计不符合第二范式：
        /*
            sid    sname      phone           blood      fathername    mothername     fatherjob    motherjob   fatherphone   motherphone
            s001   jim        13800138000     A          tom           jane           Engineer     Teacher     ...            ....
         */
        // 第三范式： 在满足第二范式的基础上，保证每个字段都只直接依赖于主键
        // 以下设计不符合第三范式：
        /*
            id    sid    sname     subid     subname     score
            1    s001   张三       c001      语文         95
            2    s001   张三       c002      数学         93
            3    s002   李四       c001      语文         88
            4    s002   李四       c002      数学         99
         */
        // 以下设计符合第三范式
         /*
            id    sid    ubid     score
            1    s001    c001      95
            2    s001    c002      93
            3    s002    c001      88
            4    s002    c002      99
         */
        // 通过以上阐述，我们知道，数据库设计的范式越高，说明数据的冗余度越小，数据库设计的越规范。
        // 但是，在实际开发的场景中，数据库的查询性能往往比数据库的规范度要重要的多！
        // 所以，实际开发时，很多场景，我们往往会牺牲数据库的规范度，允许部分数据冗余，从而获得更好的查询性能

        // 3) 杂费值列表
        List<ApartmentFeeValue> apartmentFeeValueList = apartmentFeeValueMapper.selectList(new LambdaQueryWrapper<ApartmentFeeValue>().eq(ApartmentFeeValue::getApartmentId, id));
        List<Long> feeValueIdList = apartmentFeeValueList.stream().map(ApartmentFeeValue::getFeeValueId).collect(Collectors.toList());
        List<FeeValueVo> feeValueVoList = feeValueMapper.getFeeValueVoListByFeeValueIds(feeValueIdList);

        // 4) 图片列表
        List<GraphInfo> graphInfoList = graphInfoMapper.selectList(new LambdaQueryWrapper<GraphInfo>().eq(GraphInfo::getItemId, id).eq(GraphInfo::getItemType, ItemType.APARTMENT));

        // 分别给四个关联属性赋值
        apartmentDetailVo.setGraphVoList(graphInfoList.stream().map(graphInfo -> GraphVo.builder().url(graphInfo.getUrl()).name(graphInfo.getName()).build()).collect(Collectors.toList()));
        apartmentDetailVo.setLabelInfoList(labelInfoList);
        apartmentDetailVo.setFacilityInfoList(facilityInfoList);
        apartmentDetailVo.setFeeValueVoList(feeValueVoList);

        return apartmentDetailVo;
    }

    @Override
    public void removeApartmentById(Long id) {
        //0. 删除公寓之前，必须保证所有的房间都已经删除，否则不删除公寓信息，直接抛出异常
        Long roomCount = roomInfoMapper.selectCount(new LambdaQueryWrapper<RoomInfo>().eq(RoomInfo::getApartmentId, id));
        if(roomCount>0){
            throw new LeaseException(ResultCodeEnum.DELETE_ERROR);
        }

        //2.删除公寓配套信息
        apartmentFacilityMapper.delete(new LambdaQueryWrapper<ApartmentFacility>().eq(ApartmentFacility::getApartmentId,id));

        //3.删除公寓标签信息
        apartmentLabelService.remove(new LambdaQueryWrapper<ApartmentLabel>().eq(ApartmentLabel::getApartmentId,id));

        //4.删除公寓的杂费值信息
        apartmentFeeValueMapper.delete(new LambdaQueryWrapper<ApartmentFeeValue>().eq(ApartmentFeeValue::getApartmentId,id));

        //5.删除公寓的图片信息
        graphInfoMapper.delete(new LambdaQueryWrapper<GraphInfo>().eq(GraphInfo::getItemId,id).eq(GraphInfo::getItemType,ItemType.APARTMENT));

        //1.删除公寓本身信息
        this.removeById(id);
    }
}




